/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.meducated.sim.model;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

/**
 *
 * @author Carina
 */
public class PropertyConnector<V> {

    /**
     * The property with which this connector is associated
     */
    private final Property<V> property;
    /**
     * The integrator which will resolve the value of the property associated
     * with this connector
     */
    private PropertyIntegrator<V> integrator;
    /**
     * The map of effectors exerting an effect on the property associated with
     * this connector and the most recent values output by the effectors
     */
    private final HashMap<Effector<V>, V> factors;
    /**
     * The map of properties upon which this connector is dependent
     */
    private final HashMap<Property, Class> dependencies;

    /**
     *
     * @param property
     */
    PropertyConnector(Property<V> property) {
        this.property = property;
        this.factors = new HashMap<Effector<V>, V>();
        this.dependencies = new HashMap<Property, Class>();
    }

    /**
     *
     */
    public final void integrate(double t, double dt) {
        
        V v = integrator.integrate(property, t, dt, this.property.getValue());
        
        property.setValue(t, v);
    }

    /**
     * @return the property
     */
    public Property<V> getProperty() {
        return property;
    }

    /**
     *
     * @param integrator
     */
    public void setIntegrator(PropertyIntegrator<V> integrator) {
        this.integrator = integrator;
    }

    /**
     *
     * @return
     */
    public PropertyIntegrator<V> getIntegrator() {
        return this.integrator;
    }

    /**
     * 
     * @param p 
     */
    public void putDependency(Property p) {
        this.putDependency(p, p.getValue().getClass());
    }
    /**
     * 
     * @param p 
     */
    public void putDependency(Property p, Class c) {
        this.dependencies.put(p, c);
    }
    
    /**
     * 
     * @param p 
     */
    public void removeDependency(Property p) {
        this.dependencies.remove(p);
    }
    
    /**
     * 
     * @return 
     */
    public Set <Property> getDependencies() {
        return this.dependencies.keySet();
    }
   
    
    /**
     * 
     * @return 
     */
    public boolean hasDependencies() {
        return !this.dependencies.isEmpty();
    }

    /**
     * 
     * @param e 
     */
    public void removeFactor(Effector e) {
        this.factors.remove(e);
    }

    /**
     *
     * @param e
     * @param dv
     */
    public void putFactor(Effector e, V dv) {
        this.factors.put(e, dv);
    }

    /**
     *
     * @param e
     * @return
     */
    public V getFactor(Effector e) {
        return this.factors.get(e);
    }
    
    /**
     * 
     * @return 
     */
    public Iterator<Entry<Effector<V>, V>> getFactorIterator() {
        return this.factors.entrySet().iterator();
    }
}
